package com.heima.wemedia.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.ChannelDto;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmChannelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
@Transactional
@Slf4j
public class WmChannelServiceImpl extends ServiceImpl<WmChannelMapper, WmChannel> implements WmChannelService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    /**
     * 查询所有频道
     * @return
     */
    @Override
    public ResponseResult findAll() {
        return ResponseResult.okResult(list());
    }

    /**
     * 频道名称模糊分页查询
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(ChannelDto dto) {
        // 需求
        // 1. 查询需要按照创建时间倒序查询
        // 2. 按照频道名称模糊查询
        // 3. 可以按照状态进行精确查找(1: 启用true, 0: 禁用false) 前端没传这个数据, 无法实现
        // 4. 分页查询

        // 1. 检查参数
        dto.checkParam();

        // 2. 分页查询
        IPage page = new Page(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmChannel> query = new LambdaQueryWrapper<>();
        // 2.1 按照频道名称模糊查询
        query.like(dto.getName()!=null, WmChannel::getName, dto.getName());
        // 2.2 按照创建时间倒序查询
        query.orderByDesc(WmChannel::getCreatedTime);
        // 2.3 查询结果
        page(page, query);

        // 3. 返回结果
        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        result.setData(page.getRecords());
        return result;
    }

    /**
     * 删除频道
     * @param id
     * @return
     */
    @Override
    public ResponseResult delChannel(Integer id) {
        // 需求
        // 1. 只有禁用的频道可以删除
        // 2. 频道被文章引用也不能删除

        // 1. 检查参数
        if(id == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 根据id查询频道
        // 2.1 查询频道的状态
        WmChannel wmChannel = getById(id);
        if(wmChannel.getStatus().equals(true)){
            // 启用
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "禁用的频道才可以删除");
        }

        // 2.2 查询频道是否被文章引用
        if(isRefer(id)){
            // 有文章引用
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "没有文章引用的频道才可以删除");
        }

        // 3. 删除频道
        removeById(id);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 保存频道
     * @param wmChannel
     * @return
     */
    @Override
    public ResponseResult saveChannel(WmChannel wmChannel) {
        // 需求
        // 1. 前台输入内容进行频道的保存
        // 2. 频道名称不能重复

        // 1. 检查参数
        // 1.1 频道名称和描述不能为空
        if(StringUtils.isBlank(wmChannel.getName()) || StringUtils.isBlank(wmChannel.getDescription())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "名称和描述不能为空");
        }
        // 1.2 频道排序不能为空, 且范围为[0, 255]
        if(wmChannel.getOrd() == null || wmChannel.getOrd() < 0 || wmChannel.getOrd() > 255){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "排序不能为空, 且范围为[0, 255]");
        }

        // 2. 判断频道名称是否重复
        LambdaQueryWrapper<WmChannel> query = new LambdaQueryWrapper<>();
        query.eq(WmChannel::getName, wmChannel.getName());
        query.last("limit 1");
        WmChannel channel = getOne(query);
        if(channel != null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST);
        }

        // 3. 保存频道
        wmChannel.setIsDefault(true);
        wmChannel.setCreatedTime(new Date());
        save(wmChannel);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 修改频道
     * @param wmChannel
     * @return
     */
    @Override
    public ResponseResult updateChannel(WmChannel wmChannel) {
        // 需求
        // 1. 点击编辑后可以修改频道
        // 2. 如果频道被引用则不能禁用

        // 1. 检查参数
        // 1.1 名称不能为空
        if(wmChannel.getName()!=null && StringUtils.isBlank(wmChannel.getName())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "名称不能为空");
        }
        // 1.2 描述不能为空
        if(wmChannel.getDescription()!=null && StringUtils.isBlank(wmChannel.getDescription())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "描述不能为空");
        }
        // 1.3 排序不能为空, 且范围为[0, 255]
        if(wmChannel.getOrd()!=null){
            if(wmChannel.getOrd() < 0 || wmChannel.getOrd() > 255){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "排序范围为[0, 255]");
            }
        }

        // 2. 如果频道被引用则不能禁用
        if(wmChannel.getStatus().equals(false)){
            // 2.1 查询频道是否被文章引用
            if (isRefer(wmChannel.getId())){
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "没有文章引用的频道才可以禁用");
            }
        }

        updateById(wmChannel);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 查询文章是否被引用
     * @param id
     * @return
     */
    private boolean isRefer(Integer id) {
        LambdaQueryWrapper<WmNews> query = new LambdaQueryWrapper<>();
        query.eq(WmNews::getChannelId, id);
        query.last("limit 1");
        WmNews wmNews = wmNewsMapper.selectOne(query);
        if(wmNews != null){
            // 有文章引用
            return true;
        }
        return false;
    }
}